from datetime import datetime
import logging
from controllers.errors.error import HttpAccountNotFound
from controllers.errors.online_mall.pick_addr_errors import HPickAddrNotFoundError, HPickAddrParamError
from controllers.errors.online_mall.shop_errors import HShopNotFoundError
from flask_babel import _
from controllers.errors.online_mall.user_addr_errors import HUserAddrNotFoundError
from core.entities.account_role import AccountWrap
from extensions.ext_database import db
from werkzeug.exceptions import InternalServerError
from models.account import Account
from models.online_mall.delivery import MUserAddr,MUserOrderAddr
from services.area_init_service import AreaService

class UserAddrService:
    @staticmethod
    def get_by_id(account:AccountWrap,addr_id:str)->MUserAddr|None:
        return db.session.query(MUserAddr).filter(MUserAddr.id==addr_id,MUserAddr.tenant_id==account.current_tenant_id).first()
    @staticmethod
    def get_list(account:AccountWrap,args:dict)->dict:
        try:
            query = db.session.query(MUserAddr).filter(MUserAddr.tenant_id==account.current_tenant_id)
            if 'account_id' in args and args['account_id']:
                query = query.filter(MUserAddr.account_id==args['account_id'])
            if 'receiver' in args and args['receiver']:
                query = query.filter(MUserAddr.receiver.like(f"%{args['receiver']}%"))
            if 'postal_code' in args and args['postal_code']:
                query = query.filter(MUserAddr.postal_code.like(f"%{args['postal_code']}%"))
            if 'addr' in args and args['addr']:
                query = query.filter(MUserAddr.addr.like(f"%{args['addr']}%"))
            if 'mobile' in args and args['mobile']:
                query = query.filter(MUserAddr.mobile.like(f"%{args['mobile']}%"))
            if 'status' in args and args['status'] is not None:
                query = query.filter(MUserAddr.status==args['status'])
            if 'is_default' in args and args['is_default'] is not None:
                query = query.filter(MUserAddr.is_default==args['is_default'])
            total = query.count()
            has_more = False
            if "page" in args and args["page"]>0 and "page_size" in args and args["page_size"]>0:
                query = query.offset((args["page"]-1)*args["page_size"]).limit(args["page_size"])
                has_more = total > args["page"]*args["page_size"]
            data = query.order_by(MUserAddr.created_at.desc(),MUserAddr.postal_code.desc()).all()
            return dict(
                total=total,
                has_more=has_more,
                data=data,
            )
        except Exception as e:
            logging.error(e)
            return {
                "total":0,
                "has_more":False,
                "data":[],
                "message":str(e),
            }
        
    
    @staticmethod
    def create_user_addr(account:AccountWrap,args:dict)->MUserAddr:

        user_addr = MUserAddr(
            tenant_id = account.current_tenant_id, # type: ignore
        )
        UserAddrService._fill_addr_param(account, args, user_addr)
        try:
            db.session.add(user_addr)
            db.session.commit()
            return user_addr
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))
        
    @staticmethod
    def update_user_addr(account:AccountWrap,args:dict)->MUserAddr:
        if 'id' not in args or not args['id']:
            raise HUserAddrNotFoundError(args.get("id"))
        user_addr = db.session.get(MUserAddr, args.get("id"))
        if not user_addr or user_addr.tenant_id != account.current_tenant_id:
            raise HUserAddrNotFoundError(args.get("id"))
        
        UserAddrService._fill_addr_param(account, args, user_addr)
        user_addr.updated_at = datetime.now()
        try:
            db.session.commit()
            return user_addr
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))
        
    @staticmethod
    def del_user_addr(account:AccountWrap,args:dict):
        if 'id' not in args or not args['id']:
            raise HUserAddrNotFoundError(args.get("id"))
        user_addr = db.session.get(MUserAddr, args.get("id"))
        if not user_addr or user_addr.tenant_id != account.current_tenant_id:
            raise HUserAddrNotFoundError(args.get("id"))
        try:
            db.session.delete(user_addr)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))

    @staticmethod
    def _fill_addr_param(account, args, user_addr):
        if 'account_id' in args and args['account_id']:
            user_addr.account_id = args['account_id']
        else:
            user_addr.account_id = account.id

        if 'receiver' in args and args['receiver']:
            user_addr.receiver = args['receiver']
        else:
            user = db.session.get(Account,user_addr.account_id)
            if not user:
                raise HttpAccountNotFound(user_addr.account_id)
            user_addr.receiver = user.name

        if 'mobile' in args and args['mobile']:
            user_addr.mobile = args['mobile']
        else:
            user = db.session.get(Account,user_addr.account_id)
            if not user:
                raise HttpAccountNotFound(user_addr.account_id)
            user_addr.mobile = user.phone

        if 'addr' in args and args['addr']:
            user_addr.addr = args['addr']
        
        if 'status' in args and args['status'] is not None:
            user_addr.status = args['status']

        if 'province_id' in args and args['province_id']:
            user_addr.province_id = args['province_id']
            province = AreaService.get_area_name_by_code(args['province_id'])
            user_addr.province = province

        if 'city_id' in args and args['city_id']:
            user_addr.city_id = args['city_id']
            city = AreaService.get_area_name_by_code(args['city_id'])
            user_addr.city = city

        if 'district_id' in args and args['district_id']:
            user_addr.district_id = args['district_id']
            district = AreaService.get_area_name_by_code(args['district_id'])
            user_addr.district = district

        if 'is_default' in args and args['is_default'] is not None:
            user_addr.is_default = args['is_default']